<template>
  <div ref="searchRef" class="strong-search" :class="{ active }">
    <!-- <i class="filter-icon" @click="handleInputFocus">
      <img :src="FilterSvg" alt="" />
    </i> -->
    <a-scrollbar ref="scrollbarRef" outer-class="search-scrollbar">
      <tag-group
        v-model="searchValue"
        @delete="handleSearch"
        @tag-click="handleActiveHide" />
      <a-popover
        :popup-visible="popoverVisible"
        trigger="click"
        content-class="search-popover"
        position="bl">
        <a-input
          ref="inputRef"
          v-model="inputValue"
          :max-length="maxLength"
          :placeholder="placeholder"
          class="search-input"
          @keydown="handleInputKeyDown"
          @click="handleInputFocus"
          @blur="handleInputBlur">
          <template v-if="prefix" #prefix>{{ prefix }}:</template>
          <template #suffix>
            <search-close-icon
              v-if="closeBtnVisible"
              class="e-icon"
              @click.stop="handleClear" />
            <search-icon class="e-icon" @click.stop="handleClickSearch" />
          </template>
        </a-input>
        <template #content>
          <filter-list
            v-if="filterOptions.length && popoverType === 'filterList'"
            :options="filterOptions"
            @change="handleFilterChange">
            <template #title>
              <slot name="filterListTitle" />
            </template>
          </filter-list>
          <search-select
            v-else-if="popoverType === 'select'"
            :options="selectOptions"
            @change="handleSelectChange" />
          <search-check
            v-else-if="popoverType === 'check'"
            :options="checkOptions"
            @ok="handleCheckOk"
            @cancel="handleCheckCancel" />
          <search-date
            v-else-if="popoverType === 'date'"
            :start-disabled-date="dateProps.startDisabledDate"
            :end-disabled-date="dateProps.endDisabledDate"
            @ok="handleDateOk"
            @cancel="handleDateCancel">
            <template #title>
              <slot name="dateTitle" />
            </template>
          </search-date>
        </template>
      </a-popover>
    </a-scrollbar>
  </div>
</template>
<script lang="ts" setup>
import {
  type InputInstance,
  Message,
  Notification,
  type ScrollbarInstance
} from '@arco-design/web-vue'
import { isFunction } from 'lodash-es'

import type { LabelValue } from '../../types'
import FilterList from './popover/FilterList.vue'
import type {
  FilterItem,
  PopoverOption,
  PopoverType,
  SearchValue
} from './types'
import { formatValue } from './utils'
const props = withDefaults(
  defineProps<{
    modelValue?: SearchValue[]
    filterList: FilterItem[]
    placeholder?: string
    isFilter?: boolean
  }>(),
  {
    isFilter: true,
    modelValue: () => []
  }
)

const emit = defineEmits<{
  search: [value: Record<string, any>]
  change: [value: Record<string, any>]
  'update:modelValue': [value: SearchValue[]]
}>()

defineSlots<{
  filterListTitle(): any
  dateTitle(): any
}>()

const searchRef = ref<HTMLDivElement>()
const inputRef = ref<InputInstance>()
const scrollbarRef = ref<ScrollbarInstance>()

const active = ref(false)

const prefix = ref('')

const activeFilterItem = computed(() =>
  props.filterList.find((v) => v.label === prefix.value)
)
const maxLength = computed(
  () => activeFilterItem.value?.maxLength ?? props.filterList[0]?.maxLength
)

// 默认列表第一个 field
const field = computed(() => activeFilterItem.value?.field)
const popoverType = computed<PopoverType | null>(() =>
  !prefix.value ? 'filterList' : activeFilterItem.value?.popover || null
)
const inputValue = ref('')
const searchValue = ref<SearchValue[]>([...props.modelValue])

const popoverShow = ref(false)
const popoverVisible = computed(() => {
  if (!popoverShow.value || !popoverType.value) return false
  if (popoverType.value === 'filterList' && !filterOptions.value.length)
    return false
  if (popoverType.value === 'select' && !selectOptions.value.length)
    return false
  if (popoverType.value === 'check' && !checkOptions.value.length) return false
  return true
})

// 搜索、过滤
const filterOptions = computed(() =>
  props.filterList.filter((v) => {
    const val = inputValue.value.trim()
    if (props.isFilter)
      return (
        !searchValue.value.some((item) => item.field === v.field) &&
        (!val || v.label.includes(val))
      )
    return !val || v.label.includes(val)
  })
)

const selectOptions = computed(() => {
  const val = inputValue.value.trim()
  const list = toValue(activeFilterItem.value?.popoverOption?.select || [])
  return list.filter((v) => !val || v.label.includes(val))
})

const checkOptions = computed(() => {
  const val = inputValue.value.trim()
  const list = activeFilterItem.value?.popoverOption?.check || []
  return list.filter((v) => !val || v.label.includes(val))
})

const dateProps = computed(() => {
  return {
    ...((activeFilterItem.value?.popoverOption?.dateProps ||
      {}) as PopoverOption['dateProps']),
    label: activeFilterItem.value?.label
  }
}) as ComputedRef<PopoverOption['dateProps'] & { label: string }>

const filterPlaceholder = computed(() => {
  return !activeFilterItem.value?.popover
    ? `请输入${prefix.value.toLocaleLowerCase()}`
    : `请选择${prefix.value.toLocaleLowerCase()}`
})

const placeholder = computed(() =>
  prefix.value ? filterPlaceholder.value : props.placeholder
)
const closeBtnVisible = computed(
  () => !!prefix.value || !!searchValue.value.length || !!inputValue.value
)

function handleClear() {
  inputValue.value = ''
  prefix.value = ''
  searchValue.value = []
  handleActiveHide()
  handleSearch()
}

function handleActiveHide() {
  active.value = true
  inputRef.value?.focus()
  popoverShow.value = false
}

function popoverNextTick() {
  popoverShow.value = false
  nextTick(() => {
    popoverShow.value = true
  })
  inputRef.value?.focus()
}

async function handleInputKeyDown(e: KeyboardEvent | Event) {
  const event = e as KeyboardEvent

  // 删除
  if (event.key === 'Backspace' && !inputValue.value) {
    if (prefix.value) {
      prefix.value = ''
    } else if (searchValue.value.length) {
      searchValue.value.splice(searchValue.value.length - 1, 1)
      popoverShow.value = false

      handleSearch()
    }
  }

  // 直接输入确认
  const val = inputValue.value.trim()
  if (
    val &&
    !popoverVisible.value &&
    props.filterList.length &&
    event.key === 'Enter' &&
    !activeFilterItem.value?.popover
  ) {
    autoDelFilterItem()
    const res = await setSearchValue([{ label: val, value: val }])
    if (!res) return
    prefix.value = ''
    inputValue.value = ''

    popoverShow.value = false

    handleSearch()
  }
}

function handleInputFocus() {
  active.value = true
  popoverShow.value = true
  nextTick(() => {
    inputRef.value?.focus()
  })
}

const noClosePopover = ref(false)

function handleInputBlur() {
  if (
    noClosePopover.value ||
    popoverType.value === 'select' ||
    popoverType.value === 'date'
  )
    return
  active.value = false
  popoverShow.value = false
}

watchEffect(() => {
  // 点击弹窗，不主动关闭
  const noCloseTypes: PopoverType[] = ['date', 'check']
  if (
    popoverType.value &&
    noCloseTypes.includes(popoverType.value) &&
    popoverVisible.value
  ) {
    noClosePopover.value = true
  }
})

function autoDelFilterItem() {
  const firstType =
    inputValue.value.trim() && !prefix.value ? props.filterList[0]?.field : null
  const field = activeFilterItem.value?.field || firstType
  if (!props.filterList.length || !field) return

  const idx = searchValue.value.findIndex((v) => v.field === field)
  idx > -1 && searchValue.value.splice(idx, 1)
}

async function setSearchValue(opts: LabelValue[], isDate = false) {
  const firstItem = props.filterList.at(0)!
  const dateStartKey = dateProps.value.startKey
  const dateEndKey = dateProps.value.endKey
  const value = opts.map((v) => v.value)
  const data = {
    isDate,
    options: opts,
    dateStartKey,
    dateEndKey,
    value,
    text: opts.map((v) => String(v.label)),
    label: isDate ? dateProps.value.label : prefix.value || firstItem.label,
    field: field.value || firstItem.field
  }
  const activeItem = props.filterList?.find((item) => item.field === data.field)
  if (isFunction(activeItem?.validate)) {
    const flag = (await activeItem?.validate?.(value.join(''))) || false
    if (flag) {
      searchValue.value.push(data)
      return true
    } else {
      const toast =
        activeItem?.messageModel === 'message'
          ? Message.error
          : Notification.error
      const msg = activeItem?.message || '请输入有效值'
      toast(msg)
      return false
    }
  } else {
    searchValue.value.push(data)
    return true
  }
}

function setScrollBottom() {
  const warpRef = scrollbarRef.value?.containerRef
  if (warpRef) {
    const val = warpRef!.scrollHeight - warpRef!.clientHeight
    val && scrollbarRef.value?.scrollTop(val)
  }
}

function handleFilterChange(item: FilterItem) {
  inputValue.value = ''
  prefix.value = item.label

  if (popoverType.value) {
    popoverNextTick()
  } else {
    popoverShow.value = false
  }
  setTimeout(() => {
    handleInputFocus()
  }, 1)
}

async function handleSelectChange(item: LabelValue) {
  autoDelFilterItem()

  const res = await setSearchValue([item])
  if (!res) return
  prefix.value = ''
  inputValue.value = ''
  handleActiveHide()
  handleSearch()
}

async function handleCheckOk(items: LabelValue[]) {
  noClosePopover.value = false
  autoDelFilterItem()

  const res = await setSearchValue(items)
  if (!res) return
  prefix.value = ''
  inputValue.value = ''
  handleActiveHide()
  handleSearch()
}

function handleCheckCancel() {
  noClosePopover.value = false
  prefix.value = ''
  inputValue.value = ''
  handleActiveHide()
}

async function handleDateOk(value: number[]) {
  noClosePopover.value = false
  autoDelFilterItem()
  const val = value
    .map((v) => (v ? String(v) : ''))
    .map((v) => ({ label: v, value: v }))
  const res = await setSearchValue(val, true)
  if (!res) return
  prefix.value = ''
  inputValue.value = ''
  handleActiveHide()
  handleSearch()
}

function handleDateCancel() {
  noClosePopover.value = false
  prefix.value = ''
  inputValue.value = ''
  handleActiveHide()
}

async function handleSearch() {
  await nextTick()
  emit('update:modelValue', [...searchValue.value])
  emit('search', formatValue([...searchValue.value]))
  emit('change', formatValue([...searchValue.value]))
}

async function handleClickSearch() {
  const val = inputValue.value.trim()
  if (val) {
    // 直接输入点击搜索
    if (
      !popoverVisible.value &&
      props.filterList.length &&
      !activeFilterItem.value?.popover
    ) {
      autoDelFilterItem()
      const res = await setSearchValue([{ label: val, value: val }])
      if (!res) return
    }
    if (prefix.value) prefix.value = ''
    inputValue.value = ''
  }

  handleSearch()
  handleActiveHide()
}
// watch(
//   () => props.modelValue,
//   () => {
//     console.log(props.modelValue)
//     searchValue.value = [...props.modelValue]
//   },
//   { deep: true }
// )

// 新增的才滚动
watch(
  searchValue,
  (val, oldVal) => {
    val.length > oldVal.length && setScrollBottom()
  },
  { flush: 'post' }
)
onMounted(() => {
  if (!props.filterList.length) {
    console.error('props配置 `filterList` 长度不能为 0')
  }
})

provide(
  'is-active',
  computed(() => active.value && popoverVisible.value)
)
</script>
<style lang="less">
@import './style.less';
</style>
